package com.towker.core.db;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.hql.ast.*;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.engine.SessionFactoryImplementor;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;

import com.towker.core.page.*;


/**
 * @author zyg
 */
public abstract class BaseHibernateDao<E, PK extends Serializable> extends HibernateDaoSupport implements EntityDao<E, PK>
{
	protected Log log = LogFactory.getLog(getClass());

	public long queryForLong(final String queryString)
	{
		return queryForLong(queryString, new Object[] {});
	}

	public long queryForLong(final String queryString, Object value)
	{
		return queryForLong(queryString, new Object[]
		{
			value
		});
	}
	
	
	
	/**
	 * 根据hql和PageRequest取得数据分页
	 * @param hql
	 * @param pageRequest 
	 * PageRequest的Filters是一个list ，list中的数据是条件

	 * @return
	 */
	@SuppressWarnings("unchecked")
	public PageModel getPageByHql(String hql, PageRequest pageRequest)
	{
		List conditionList = new ArrayList();
		if (pageRequest.getFilters() instanceof List)
		{
			List list = (List) pageRequest.getFilters();
			conditionList.addAll(list);
		}
		int totalCount = getTotal(hql, conditionList).intValue();
		PageModel page = new PageModel(pageRequest, totalCount);
		List list = getByHql(hql, conditionList, pageRequest.getCurrentPage(), pageRequest.getPageSize());
		page.setResult(list);
		return page;
	}

	/**
	 * 根据hql和参数查询分页

	 * @param hql hql语句
	 * @param list 参数列表
	 * @param currentPage 当前页

	 * @param pageSize 页大小

	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<E> getByHql(final String hql, final List list, final int currentPage, final int pageSize)
	{
		return (List) getHibernateTemplate().execute(new HibernateCallback()
		{
			public Object doInHibernate(Session session)
			{
				Query query = session.createQuery(hql);
				int first = (currentPage - 1) * pageSize;
				query.setFirstResult(first).setMaxResults(pageSize);
				for (int i = 0; i < list.size(); i++)
				{
					query.setParameter(i, list.get(i));
				}
				return query.list();
			}
		});
	}

	/**
	 * 根据hql和参数列表取得记录列表

	 * @param hql
	 * @param list
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<E> getByHql(final String hql, final List list)
	{
		return (List) getHibernateTemplate().execute(new HibernateCallback()
		{
			public Object doInHibernate(Session session)
			{
				Query query = session.createQuery(hql);
				for (int i = 0; i < list.size(); i++)
				{
					query.setParameter(i, list.get(i));
				}
				return query.list();
			}
		});
	}

	/**
	 * 根据hql和条件列表取得记录的总数
	 * @param queryString
	 * @param list
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Long getTotal(String hql, final List list)
	{
		int orderByIndex = hql.toUpperCase().indexOf(" ORDER BY ");
		if (orderByIndex != -1)
		{
			hql = hql.substring(0, orderByIndex);
		}
		QueryTranslatorImpl queryTranslator = new QueryTranslatorImpl(hql, hql, Collections.EMPTY_MAP, (SessionFactoryImplementor) getSessionFactory());
		queryTranslator.compile(Collections.EMPTY_MAP, false);
		final String sql = "select count(*) from (" + queryTranslator.getSQLString() + ") tmp_count_t";
		Object reVal = getHibernateTemplate().execute(new HibernateCallback()
		{
			public Object doInHibernate(Session session) throws HibernateException, SQLException
			{
				SQLQuery query = session.createSQLQuery(sql);
				for (int i = 0; i < list.size(); i++)
				{
					query.setParameter(i, list.get(i));
				}
				return query.uniqueResult();
			}
		});
		return new Long(reVal.toString());
	}
	
	/**
	 * 根据hql和参数取得long型数据

	 * @param queryString
	 * @param values
	 * @return
	 */
	public long queryForLong(final String hql, Object[] values)
	{
		return DataAccessUtils.longResult(getHibernateTemplate().find(hql, values));
	}
	
	public PageModel getPage(final PageRequest pageRequest)
	{
		return getAll(pageRequest);
	}

	/**
	 * 得到全部数据,但执行分页

	 * @param pageRequest
	 * @return
	 */
	public PageModel getAll(final PageRequest pageRequest)
	{
		StringBuffer queryString = new StringBuffer(" FROM ").append(getEntityClass().getSimpleName());
		return getPageByHql(queryString.toString(), pageRequest);
	}

	public List<E> getAll()
	{
		return getHibernateTemplate().loadAll(getEntityClass());
	}
	/**
	 * 根据id取得实体数据
	 */
	public E getById(PK id)
	{
		return (E) getHibernateTemplate().get(getEntityClass(), id);
	}
	
	/**
	 * 添加对象
	 */
	public void add(E entity)
	{
		// TODO Auto-generated method stub
		getHibernateTemplate().save(entity);
	}
	
	/**
	 * 删除对象
	 * @param entity
	 */
	public void delete(E entity)
	{
		getHibernateTemplate().delete(entity);
	}
	
	
	/**
	 * 根据ID删除
	 * 先加载对象，在进行删除

	 */
	public int delById(PK id)
	{
		E entity = getById(id);
		if (entity == null)
		{
			throw new ObjectRetrievalFailureException(getEntityClass(), id);
		}
		getHibernateTemplate().delete(entity);
		return 1;
	}

	/**
	 * 更新实体对象
	 */
	public int update(E entity)
	{
		getHibernateTemplate().update(entity);
		return 1;
	}

	/**
	 * 更新或添加实体对象

	 * @param entity
	 */
	public void saveOrUpdate(E entity)
	{
		getHibernateTemplate().saveOrUpdate(entity);
	}

	public void refresh(Object entity)
	{
		getHibernateTemplate().refresh(entity);
	}
	
	
	public void flush()
	{
		getHibernateTemplate().flush();
	}

	public void evict(Object entity)
	{
		getHibernateTemplate().evict(entity);
	}

	public void saveAll(Collection<E> entities)
	{
		for (Iterator<E> it = entities.iterator(); it.hasNext();)
		{
			add(it.next());
		}
	}

	public void deleteAll(Collection entities)
	{
		getHibernateTemplate().deleteAll(entities);
	}

	public abstract Class getEntityClass();
}
